/*
 * yocef - Lightweight IoC Event Framework
 *
 * Copyright (c) 2009, Yves Cuillerdier
 * All rights reserved.
 * 
 * This software is licensed under the new BSD License:
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution.
 * 
 * Neither the name of the author nor the names of its contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * @version 0.8.3
 */

package yocef.client;

import java.util.Map;
import java.util.TreeMap;

/**
 * This class is the glue between the <tt>Event</tt>s and the "outside world".
 * <p>
 * Instances of this class have to be provided to specify how the Event is tight
 * with the source Object.
 * <p>
 * An EventGlue instance is theoretically to be write for each possible source
 * class. However, thanks to Class inheritance, very few are to write.
 * <p>
 * The same glue object could be used for more than one class. On the other
 * hand, a given class have at max one glue object.
 */
public abstract class EventGlue {

	/**
	 * Map between elements class name and glue objects.
	 * <p>
	 * These associations will be generally have the same live time as the
	 * application.
	 * <p>
	 * Key is the class name
	 */
	private static final Map<String, EventGlue> glueStock = new TreeMap<String, EventGlue>();

	/**
	 * Register a class with a glue object instance.
	 * 
	 * @param objClass
	 *            the class associated with the glue object.
	 * @param glue
	 *            the glue for the given class
	 */
	public static void register(final Class<?> objClass, final EventGlue glue) {
		glueStock.put(objClass.getName(), glue);
	}

	/**
	 * Get the glue object registered with a given class.
	 * 
	 * @param objClass
	 *            the class for witch we try to get an EventGlue
	 * @return the glue object for the given class or null
	 */
	public static EventGlue get(final Class<?> objClass) {
		return glueStock.get(objClass.getName());
	}

	/**
	 * Remove an association for the given class.
	 * <p>
	 * This method is unlikely to be used as, generally,
	 * <tt>{Class,EventGlue}</tt> association remains for all the application
	 * session. Anyway ...
	 * 
	 * @param objClass
	 *            the class to unregister
	 */
	public static void unRegister(final Class<?> objClass) {
		glueStock.remove(objClass.getName());
	}

	/**
	 * Create an EventGlue.
	 * <p>
	 * This glue object will have to be registered with a class
	 */
	public EventGlue() {
		super();
	}

	/**
	 * Create an EventGlue and register it for the provided class.
	 * 
	 * @param objClass
	 *            the class to register with the glue instance
	 */
	public EventGlue(final Class<?> objClass) {
		super();
		register(objClass, this);
	}

	/**
	 * Do the actual binding of the <tt>Event</tt> with the source
	 * <tt>Object</tt>.
	 * <p>
	 * If the event is native to the source object, this method must:
	 * <ul>
	 * <li>register a listener instance in the source object.</li>
	 * <li>return true to acknowledge for processing</li>
	 * </ul>
	 * For its part, the Listener must:
	 * <ul>
	 * <li>get the native event object and prepare an {@link EventParameter}
	 * object.</li>
	 * <li>call the
	 * {@link EventAction#handle(Event, Object, EventContext, EventParams)}
	 * method with the needed parameters</li>
	 * </ul>
	 * <p>
	 * If the event is not native (custom event), this method must:
	 * <ul>
	 * <li>Simply return true as the {@link Event#fire(Object, EventParams)}
	 * will do all the job.</li>
	 * </ul>
	 * If this method is called for an Event type that is not supported (or the
	 * glue don't want to process), it must responds <tt>false</tt> to
	 * allow the calling {@link EventBind#now()} method to continue its search
	 * up the source object superclass.
	 * 
	 * @param binding
	 *            The EventBind defining the <tt>Event</tt>, source
	 *            <tt>Object</tt>, action (defining the
	 *            {@link EventAction#handle(Event, Object, EventContext, EventParams)}
	 *            ) and the context
	 * @return true if the binding has been accepted and processed or false
	 */
	public abstract boolean accept(EventBind binding);

	/**
	 * Remove the binding between the <tt>Event</tt> and the source
	 * <tt>Object</tt>.
	 * <p>
	 * If the event is native in the source object, this method must:
	 * <ul>
	 * <li>unregister the listener instance from the source object.</li>
	 * <li>respond <tt>true</tt> to acknowledge for processing</li>
	 * </ul>
	 * If the event is not native (custom event), this method must:
	 * <ul>
	 * <li>respond <tt>true</tt></li>
	 * </ul>
	 * Notice that, for a given Event type, the two methods
	 * {@link EventGlue#accept(Event, Object)} and
	 * {@link EventGlue#free(EventBind)} must gave the same response.
	 * 
	 * @param binding
	 *            The EventBind defining the <tt>Event</tt>, source
	 *            <tt>Object</tt>, action (defining the
	 *            {@link EventAction#handle(Event, Object, EventContext, EventParams)}
	 *            ) and the context
	 * @return true if the source object has been released from event, or else
	 *         false
	 */
	public abstract boolean release(EventBind binding);
}
